// bitmap 位向量简单存储
// set 设置基础列表(item 项不唯一)
// checkBit 检查基础列表中，是否存在这个值（同时输出个数）
//
// X横坐标，最大值m
// Y纵坐标，最大值n
// Bitmap(m，n)
// Y/n值可叠加
// 初始 n值为0
// Bitmap.bitSet n值累加
// Bitmap.checkBit 输出n值

class Bitmap {
  constructor(numberSize = 10, boxMaxSize = 1) {
    this.MAX_SIZE = boxMaxSize
    this.INPUT_NUMBER_SIZE = numberSize

    this.calculateZoneSize()
    this.calculateByteSize()
    // 创建-适当大小的buf
    this.buf = Buffer.alloc(this.BYTE_SIZE, 0, 'binary')
  }
  // 计算需要所需要的 字节数
  calculateByteSize() {
    let bitSize = this.ZONE_SIZE * this.INPUT_NUMBER_SIZE
    let byteSize = bitSize >> 3
    this.BYTE_SIZE = byteSize + (bitSize & 0x07 ? 1 : 0)
  }
  // 计算存储一个数据的空间
  calculateZoneSize() {
    let midValue = this.MAX_SIZE
    for (let i = 1; true; i++) {
      if (!(midValue = midValue >> 1)) {
        this.ZONE_SIZE = i
        break
      }
    }
  }

  bitSet(number, count) {
    if (!this.inputValidity(number, count)) return
    let beyondList = this.getBit(number)

    // 取值
    let bitValue = this.mergeBit(beyondList)
    // 判断是否 增加
    let newCount = bitValue + count

    if (newCount > this.MAX_SIZE) {
      console.log(
        `该Bitmap每个ITEM容纳个数为：${this.MAX_SIZE}，此ITEM已容纳${bitValue},需要添加${count}个，已超出！`
      )
      return
    }

    // 拆封成 beyondlist
    let resBeyondList = this.splitBit(newCount, beyondList)

    // console.log('result', JSON.parse(JSON.stringify(resBeyondList)))

    this.setBufBit(resBeyondList)
  }

  checkBit(number) {
    if (!this.inputValidity(number)) return
    let beyondList = this.getBit(number)

    // 取值
    let bitValue = this.mergeBit(beyondList)

    console.log(`checkBit number:${number} , value:${bitValue}`)
  }
  // 位-抓取
  getBit(number) {
    let beyondList = []
    let biteIndex = (number - 1) * this.ZONE_SIZE
    let byteIndex = (biteIndex >> 3) - 1
    let byteRemainder = biteIndex & 0x07

    // 定位出-字节中存数据的 x 位 （x-1位）
    let byteInBinaryIndex = 0

    // 存在余数的情况下 字节定位出的索引值加一
    if (byteRemainder) {
      byteIndex += 1
      byteInBinaryIndex = byteRemainder
    } else if (number === 1 || biteIndex % this.ZONE_SIZE === 0) {
      byteIndex += 1
    }

    // 存储值
    let data = 0
    // 当前字节中的存储值
    let value = 0

    // 距离下一个临界的距离
    let terminateValue = 8 - byteInBinaryIndex
    // 所需空间
    let lostZoneSize = this.ZONE_SIZE

    do {
      if (terminateValue < lostZoneSize) {
        // 当前范围内的位值
        value = this.buf[byteIndex] & ((1 << terminateValue) - 1)

        lostZoneSize -= terminateValue

        // 记录取值位置
        beyondList.push({
          value,
          byteIndex,
          offset: byteInBinaryIndex,
          size: terminateValue,
          lastSize: lostZoneSize
        })

        // 用于下次循环
        terminateValue = 8
        byteIndex += 1
        byteInBinaryIndex = 0
        continue
      }
      // moduleBinary
      let leftMove = 8 - lostZoneSize - byteInBinaryIndex
      let binary = (1 << lostZoneSize) - 1
      let moduleBinary = binary << leftMove
      // 取值
      value = (this.buf[byteIndex] & moduleBinary) >> leftMove

      beyondList.push({
        value,
        byteIndex,
        offset: byteInBinaryIndex,
        size: lostZoneSize,
        lastSize: 0
      })
      break
    } while (true)

    return beyondList
  }
  // 合并拆分出的 位
  mergeBit(beyondList) {
    let bitValue = 0
    for (let i = 0, length = beyondList.length; i < length; i++) {
      bitValue |= beyondList[i].value << beyondList[i].lastSize
    }
    return bitValue
  }
  // 拆分合并的 位
  splitBit(bitVal, beyondList) {
    for (let i = 0, length = beyondList.length; i < length; i++) {
      beyondList[i].value =
        // 计算出，当前字节下 新的value
        (bitVal &
          (((1 << beyondList[i].size) - 1) << beyondList[i].lastSize)) >>
        beyondList[i].lastSize
    }
    return beyondList
  }
  // 位-赋值到buffer上
  setBufBit(resBeyondList) {
    for (let i = 0, length = resBeyondList.length; i < length; i++) {
      let { value, offset, size, byteIndex } = resBeyondList[i]
      // byte
      let byteBuf = this.buf[byteIndex]
      // 准备替换模版
      let moduleBuf = 0
      {
        offset && (moduleBuf |= (1 << offset) - 1) // 替代位前几位 1代替
        moduleBuf <<= size // 腾出替换位，0代替
        // 替代位后几位，1代替
        moduleBuf <<= 8 - size - offset
        moduleBuf |= (1 << (8 - size - offset)) - 1
      }
      // 清空需要替换位
      byteBuf &= moduleBuf
      // 在清空位上-赋上真实的位值
      let realBuf = value
      {
        realBuf <<= 8 - size - offset
      }

      byteBuf |= realBuf
      // 赋值
      this.buf[byteIndex] = byteBuf
    }
  }

  inputValidity(number, count) {
    if (number < 1 || number > this.INPUT_NUMBER_SIZE) {
      console.log(
        `被操作Bitmap对象的number值范围：[1,${this.INPUT_NUMBER_SIZE}]`
      )
      return false
    }
    if (count < 0 || count > this.MAX_SIZE) {
      console.log(`被操作Bitmap对象的size值范围：[0,${this.MAX_SIZE})`)
      return false
    }
    return true
  }
}

// max_size 开区间
let bitMap = new Bitmap(1000, 1025)
// set
bitMap.bitSet(1, 1023)
bitMap.bitSet(103, 216)
bitMap.bitSet(37, 231)
bitMap.bitSet(361, 177)
// check
bitMap.checkBit(3)
bitMap.checkBit(103)
bitMap.checkBit(37)
bitMap.checkBit(361)

console.log('-------')
console.log(bitMap)
